"""
版本管理数据模型
包含版本、版本关联、发布记录等相关模型
"""
from datetime import datetime
from typing import Optional, List, Dict, Any
from enum import Enum
from pydantic import BaseModel, Field, validator  # pyright: ignore[reportMissingImports]
from .base import PyObjectId


# 版本状态通过state模块进行管理，使用字符串类型

class RelationType(str, Enum):
    """关联类型枚举"""
    INCLUDED = "included"
    BLOCKED_BY = "blocked_by"
    DEPENDS_ON = "depends_on"
    FOUND_IN = "found_in"
    FIXED_IN = "fixed_in"


class ReleaseType(str, Enum):
    """发布类型枚举"""
    MAJOR = "major"
    MINOR = "minor"
    PATCH = "patch"
    HOTFIX = "hotfix"


class VersionType(str, Enum):
    """版本类型枚举"""
    FEATURE = "feature"
    BUGFIX = "bugfix"
    HOTFIX = "hotfix"
    MAINTENANCE = "maintenance"
    SECURITY = "security"


class Environment(str, Enum):
    """环境枚举"""
    DEVELOPMENT = "development"
    TESTING = "testing"
    STAGING = "staging"
    PRODUCTION = "production"


class ReleaseStatus(str, Enum):
    """发布状态枚举"""
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    FAILED = "failed"
    ROLLED_BACK = "rolled_back"


class VersionGoalStatus(str, Enum):
    """版本目标状态枚举"""
    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"


class VersionGoal(BaseModel):
    """版本目标项"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id", description="目标ID")
    title: str = Field(..., min_length=1, max_length=100, description="目标标题")
    description: Optional[str] = Field(None, max_length=1000, description="目标描述")
    status: VersionGoalStatus = Field(default=VersionGoalStatus.NOT_STARTED, description="目标状态")
    owner: Optional[str] = Field(None, max_length=100, description="负责人")
    due_date: Optional[datetime] = Field(None, description="目标截止日期")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat() if v else None,
        }


class ReleaseConfig(BaseModel):
    """发布配置模型"""
    environment: str = Field(..., description="发布环境")
    deployment_strategy: str = Field(default="rolling", description="部署策略")
    rollback_strategy: str = Field(default="manual", description="回滚策略")
    approval_required: bool = Field(default=True, description="是否需要审批")


class ReleaseMetadata(BaseModel):
    """发布元数据模型"""
    build_number: Optional[str] = Field(None, description="构建号")
    commit_hash: Optional[str] = Field(None, description="提交哈希")
    deployment_time: Optional[int] = Field(None, description="部署时间(秒)")
    rollback_available: bool = Field(default=True, description="是否可回滚")


# 基础版本模型
class VersionBase(BaseModel):
    """版本基础模型"""
    name: str = Field(..., min_length=1, max_length=100, description="版本名称")
    version_number: str = Field(..., description="版本号")
    project_id: PyObjectId = Field(..., description="关联项目ID")
    description: Optional[str] = Field(None, max_length=1000, description="版本描述")
    start_date: Optional[datetime] = Field(None, description="版本开始日期")
    end_date: Optional[datetime] = Field(None, description="版本结束日期")
    planned_release_date: Optional[datetime] = Field(None, description="计划发布时间")
    planned_work_hours: float = Field(0.0, ge=0, description="规划工时（小时）")
    release_config: Optional[ReleaseConfig] = Field(None, description="发布配置")
    goals: List[VersionGoal] = Field(default_factory=list, description="版本目标列表")
    is_pinned: bool = Field(default=False, description="是否置顶")

    @validator('version_number')
    def validate_version_number(cls, v):
        """验证版本号格式"""
        import re
        if not re.match(r'^[0-9]+\.[0-9]+\.[0-9]+.*$', v):
            raise ValueError('版本号格式不正确，应为 x.y.z 格式')
        return v
    
    @validator('end_date')
    def validate_date_range(cls, end_date: Optional[datetime], values: Dict[str, Any]) -> Optional[datetime]:
        """确保结束日期不早于开始日期"""
        start_date = values.get('start_date')
        if end_date and start_date and end_date < start_date:
            raise ValueError('结束日期不能早于开始日期')
        return end_date


class VersionCreate(VersionBase):
    """创建版本模型"""
    status: Optional[str] = Field(default="", description="版本状态（从状态管理系统动态获取，创建时使用默认状态）")
    release_type: Optional[ReleaseType] = Field(None, description="发布类型")
    environment: Optional[Environment] = Field(None, description="发布环境")
    release_notes: Optional[str] = Field(None, max_length=2000, description="发布说明")
    metadata: Optional[Dict[str, Any]] = Field(None, description="版本元数据")


class VersionUpdate(BaseModel):
    """更新版本模型"""
    name: Optional[str] = Field(None, min_length=1, max_length=100, description="版本名称")
    version_number: Optional[str] = Field(None, description="版本号")
    description: Optional[str] = Field(None, max_length=1000, description="版本描述")
    start_date: Optional[datetime] = Field(None, description="版本开始日期")
    end_date: Optional[datetime] = Field(None, description="版本结束日期")
    planned_release_date: Optional[datetime] = Field(None, description="计划发布时间")
    planned_work_hours: Optional[float] = Field(None, ge=0, description="规划工时（小时）")
    release_config: Optional[ReleaseConfig] = Field(None, description="发布配置")
    status: Optional[str] = Field(None, description="版本状态")
    is_pinned: Optional[bool] = Field(None, description="是否置顶")
    
    @validator('version_number', pre=True)
    def validate_version_number(cls, v):
        """验证版本号格式（如果提供）"""
        if v is None:
            return v
        import re
        if not re.match(r'^[0-9]+\.[0-9]+\.[0-9]+.*$', v):
            raise ValueError('版本号格式不正确，应为 x.y.z 格式')
        return v


class Version(VersionBase):
    """版本完整模型"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    status: str = Field(default="", description="版本状态（从状态管理系统动态获取，创建时使用默认状态）")
    actual_release_date: Optional[datetime] = Field(None, description="实际发布时间")
    created_by: PyObjectId = Field(..., description="创建者ID")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
    updated_at: datetime = Field(default_factory=datetime.utcnow, description="更新时间")
    is_archived: bool = Field(default=False, description="是否已归档")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat()
        }


# 版本任务关联模型
class VersionTaskRelationBase(BaseModel):
    """版本任务关联基础模型"""
    version_id: PyObjectId = Field(..., description="版本ID")
    task_id: PyObjectId = Field(..., description="任务ID")
    requirement_id: Optional[PyObjectId] = Field(None, description="关联的需求ID")
    relation_type: RelationType = Field(default=RelationType.INCLUDED, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionTaskRelationCreate(BaseModel):
    """创建版本任务关联模型（不包含version_id，因为它在URL路径中）"""
    task_id: PyObjectId = Field(..., description="任务ID")
    requirement_id: Optional[PyObjectId] = Field(None, description="关联的需求ID")
    relation_type: RelationType = Field(default=RelationType.INCLUDED, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionTaskRelation(VersionTaskRelationBase):
    """版本任务关联完整模型"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
    created_by: PyObjectId = Field(..., description="创建者ID")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat()
        }


# 版本缺陷关联模型
class VersionDefectRelationBase(BaseModel):
    """版本缺陷关联基础模型"""
    version_id: PyObjectId = Field(..., description="版本ID")
    defect_id: PyObjectId = Field(..., description="缺陷ID")
    requirement_id: Optional[PyObjectId] = Field(None, description="关联的需求ID")
    task_id: Optional[PyObjectId] = Field(None, description="关联的任务ID")
    parent_defect_id: Optional[PyObjectId] = Field(None, description="父缺陷ID，用于缺陷树")
    relation_type: RelationType = Field(default=RelationType.FOUND_IN, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionDefectRelationCreate(BaseModel):
    """创建版本缺陷关联模型（不包含version_id，因为它在URL路径中）"""
    defect_id: PyObjectId = Field(..., description="缺陷ID")
    requirement_id: Optional[PyObjectId] = Field(None, description="关联的需求ID")
    task_id: Optional[PyObjectId] = Field(None, description="关联的任务ID")
    parent_defect_id: Optional[PyObjectId] = Field(None, description="父缺陷ID，用于缺陷树")
    relation_type: RelationType = Field(default=RelationType.FOUND_IN, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionDefectRelation(VersionDefectRelationBase):
    """版本缺陷关联完整模型"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
    created_by: PyObjectId = Field(..., description="创建者ID")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat()
        }


# 发布记录模型
class ReleaseRecordBase(BaseModel):
    """发布记录基础模型"""
    version_id: PyObjectId = Field(..., description="版本ID")
    release_type: ReleaseType = Field(..., description="发布类型")
    environment: Environment = Field(..., description="发布环境")
    release_notes: Optional[str] = Field(None, max_length=2000, description="发布说明")
    release_date: datetime = Field(default_factory=datetime.utcnow, description="发布时间")


class ReleaseRecordCreate(ReleaseRecordBase):
    """创建发布记录模型"""
    pass


class ReleaseRecord(ReleaseRecordBase):
    """发布记录完整模型"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    status: str = Field(default="pending", description="发布状态")
    rollback_date: Optional[datetime] = Field(None, description="回滚时间")
    rollback_reason: Optional[str] = Field(None, max_length=500, description="回滚原因")
    released_by: PyObjectId = Field(..., description="发布者ID")
    release_metadata: Optional[ReleaseMetadata] = Field(None, description="发布元数据")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat()
        }


# 发布和回滚请求模型
# 注意：响应模型已移至 app.schemas.version 中
class ReleaseRequest(BaseModel):
    """发布请求模型"""
    release_notes: Optional[str] = Field(None, description="发布说明")
    release_date: Optional[datetime] = Field(None, description="发布时间")
    environment: Environment = Field(..., description="发布环境")
    release_metadata: Optional[ReleaseMetadata] = Field(None, description="发布元数据")


class RollbackRequest(BaseModel):
    """回滚请求模型"""
    rollback_reason: str = Field(..., description="回滚原因")
    target_version_id: Optional[PyObjectId] = Field(None, description="回滚目标版本ID")


# 版本需求关联模型
class VersionRequirementBase(BaseModel):
    """版本需求关联基础模型"""
    version_id: PyObjectId = Field(..., description="版本ID")
    requirement_id: PyObjectId = Field(..., description="需求ID")
    relation_type: RelationType = Field(default=RelationType.INCLUDED, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionRequirementCreate(BaseModel):
    """创建版本需求关联模型（不包含version_id，因为它在URL路径中）"""
    requirement_id: PyObjectId = Field(..., description="需求ID")
    relation_type: RelationType = Field(default=RelationType.INCLUDED, description="关联类型")
    notes: Optional[str] = Field(None, description="备注")


class VersionRequirement(VersionRequirementBase):
    """版本需求关联完整模型"""
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
    created_by: PyObjectId = Field(..., description="创建者ID")

    class Config:
        populate_by_name = True
        json_encoders = {
            PyObjectId: str,
            datetime: lambda v: v.isoformat()
        }
        from_attributes = True